package xcmg.device.service.warehouse;

import com.github.pagehelper.PageInfo;
import org.apache.poi.ss.usermodel.CellType;
import yb.ecp.fast.infra.util.PageHelperPlus;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.DataDictionaryDO;
import xcmg.device.dao.entity.MaterialLocationRelationDO;
import xcmg.device.dao.entity.PubMaterialsDO;
import xcmg.device.dao.entity.barcode.BarcodeManageDO;
import xcmg.device.dao.entity.initialInventory.InitialInventoryDO;
import xcmg.device.dao.entity.initialInventory.InitialInventoryDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundRecordDO;
import xcmg.device.dao.mapper.BarcodeManageMapper;
import xcmg.device.dao.mapper.DataDictionaryMapper;
import xcmg.device.dao.mapper.MaterialLocationRelationMapper;
import xcmg.device.dao.mapper.PubMaterialsMapper;
import xcmg.device.dao.mapper.initialInventory.InitialInventoryDetailMapper;
import xcmg.device.dao.mapper.initialInventory.InitialInventoryMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseAreaLocationDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundRecordMapper;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.FileUtil;
import xcmg.device.infra.ImportUtil;
import xcmg.device.infra.enums.BarcodeStatus;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.service.GenDocumentService;
import xcmg.device.service.basic.MaterialsService;
import xcmg.device.service.vo.barcode.BarcodeManageVO;
import xcmg.device.service.vo.basic.MaterialsVO;
import xcmg.device.service.vo.initialInventory.InitialInventoryDetailVO;
import xcmg.device.service.vo.initialInventory.InitialInventoryShowVO;
import xcmg.device.service.vo.initialInventory.InitialInventoryVO;
import xcmg.device.service.vo.initialInventory.MaterialsListVO;
import xcmg.device.service.vo.warehouse.UpdatePrintNumVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundAddVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundDetailVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundRecordAddVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundVO;
import xcmg.device.util.DecimalUtil;
import xcmg.device.util.RedisConstant;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.Ref;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author
 * @create 2018-03-20 19:17
 **/
@Slf4j
@Service
public class InitialInventoryService
{
    @Autowired
    private HttpServletResponse response;
    @Autowired
    private MaterialsService materialsService;

    @Autowired
    private InitialInventoryDetailService initialInventoryDetailService;

    @Autowired
    private InitialInventoryMapper initialInventoryMapper;

    @Autowired
    private InitialInventoryDetailMapper initialInventoryDetailMapper;

    @Autowired
    private DataDictionaryMapper dataDictionaryMapper;

    @Autowired
    private BarcodeManageMapper barcodeManageMapper;

    @Autowired
    private GenDocumentService genDocumentService;

    @Autowired
    private WarehouseInboundService warehouseInboundService;

    @Autowired
    private WarehouseInboundDetailService warehouseInboundDetailService;

    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private WarehouseInboundMapper warehouseInboundMapper;

    @Autowired
    private WarehouseInboundDetailMapper warehouseInboundDetailMapper;

    @Autowired
    private MaterialLocationRelationMapper materialLocationRelationMapper;
    @Autowired
    private WarehouseAreaLocationDOMapper warehouseAreaLocationDOMapper;

    @Autowired
    private WarehouseInboundRecordMapper warehouseInboundRecordMapper;
    @Autowired
    private WarehouseInventoryService warehouseInventoryService;
    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private PubMaterialsMapper pubMaterialsMapper;

    @Value("${spring.file.download.path}")
    private String filePath;

    private String templateExcelFileName = "InitialInventoryImport.xls";

    private String drivesName = "Lodop6.221_CLodop3.037.zip";
    //期初入库自动入库错误日志写入文件
    private static final String INITIALINVENROTY_INBOUND_ERROR_LOG = "initialinventory_inbound_error.log";

    /**
     * 期初入库打印，查询零件集合
     *
     * @param condition SearchCommonVO<MaterialsListVO>
     * @return PageCommonVO
     */
    public PageCommonVO listMaterials(SearchCommonVO<MaterialsListVO> condition)
    {
        PageCommonVO<InitialInventoryDetailVO> result = new PageCommonVO<>();
        List<InitialInventoryDetailVO> voList = new ArrayList<>();

        if (!StringUtil.isNullOrSpace(condition.getFilters().getMaterialsNos()))
        {
            condition.getFilters().setMaterialsNoList(getMaterialsNoList(condition.getFilters().getMaterialsNos()));
        }

        InitialInventoryDO inventoryDO = initialInventoryMapper.itemByNo(condition.getFilters().getBillNo());
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize(), "CREATE_DATE DESC");
        List<InitialInventoryDetailDO> doList = initialInventoryDetailMapper.list(condition.getFilters());
        for (InitialInventoryDetailDO entity : doList)
        {

            InitialInventoryDetailVO detailVO = new InitialInventoryDetailVO();
            BeanUtils.copyProperties(entity, detailVO);
            detailVO.setStateDesc(getStateDesc(entity.getState()));
            if(inventoryDO != null){
                detailVO.setLocation(inventoryDO.getInLocation());
                detailVO.setAreaCode(inventoryDO.getInArea());
                MaterialLocationRelationDO relationDO = materialLocationRelationMapper.findByAreaCode(entity.getMaterialsNo(), inventoryDO.getInLocation(), inventoryDO.getOrgId());
                if (relationDO!=null){
                    detailVO.setLocationCode(relationDO.getLocationCode());
                }
            }
            voList.add(detailVO);
        }

        result.setPageInfo(new PageInfo(doList));
        result.setPageInfoList(voList);
        return result;
    }

    /**
     * 获取期初入库单列表
     *
     * @param condition
     * @return
     */
    public PageCommonVO listBill(SearchCommonVO<InitialInventoryVO> condition)
    {
        PageCommonVO<InitialInventoryVO> result = new PageCommonVO<>();
        List<InitialInventoryVO> voList = new ArrayList<>();
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize(), "CREATE_DATE DESC");

        List<InitialInventoryDO> doList = initialInventoryMapper.list(condition.getFilters());

        for (InitialInventoryDO entity : doList)
        {
            InitialInventoryVO detailVO = new InitialInventoryVO();
            BeanUtils.copyProperties(entity, detailVO);
            detailVO.setStateDesc(getStateDesc(entity.getState()));
            voList.add(detailVO);
        }
        result.setPageInfo(new PageInfo(doList));
        result.setPageInfoList(voList);
        return result;
    }

    /**
     * 查询期初入库单详情
     * @param id String
     * @return InitialInventoryShowVO
     */
    public InitialInventoryShowVO item(String id)
    {
        InitialInventoryShowVO showVO = new InitialInventoryShowVO();
        List<InitialInventoryDetailVO> detailVOs = new ArrayList<>();

        InitialInventoryDO initialInventoryDO = initialInventoryMapper.item(id);
        InitialInventoryVO initialInventoryVO = new InitialInventoryVO();
        BeanUtils.copyProperties(initialInventoryDO, initialInventoryVO);

        List<InitialInventoryDetailDO> detailDOs = initialInventoryDetailMapper.listByMainId(initialInventoryDO.getId());

        for (InitialInventoryDetailDO temp : detailDOs)
        {
            InitialInventoryDetailVO detailVO = new InitialInventoryDetailVO();
            BeanUtils.copyProperties(temp, detailVO);

            String loactionCode = detailVO.getStockLocation();
            if (StringUtils.isNotBlank(loactionCode)){
                detailVO.setLocationDesc(warehouseAreaLocationDOMapper.getLocationDesc(loactionCode));
            }
            detailVOs.add(detailVO);
        }
        showVO.setHeaderInfo(initialInventoryVO);
        showVO.setDetailList(detailVOs);


        return showVO;
    }

    /**
     * 期初条码打印
     *
     * @param ids      List<String>
     * @param orgId    String
     * @param userId   String
     * @param userName String
     * @return ErrorCode
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode batchPrint(List<String> ids, String orgId, String userId, String userName, Ref<List<BarcodeManageVO>> resultRef) throws Exception
    {
        List<UpdatePrintNumVO> updatePrintNumVOList = new ArrayList<>();
        List<BarcodeManageVO> rspList = new ArrayList<>();
        for (String id : ids)
        {
            InitialInventoryDetailDO detailDO = initialInventoryDetailMapper.item(id);
            InitialInventoryDO initialInventoryDO = initialInventoryMapper.item(detailDO.getMainId());

            Ref<List<BarcodeManageVO>> printRef = new Ref<>(new ArrayList<>());

            ErrorCode resultCode = printBarcodeDOList(detailDO, orgId, userId, userName, initialInventoryDO, printRef);
            if (ErrorCode.Success != resultCode)
            {
                throw new Exception(resultCode.getDesc());
            }
            initialInventoryDetailMapper.updateAfterPrint(id);
            UpdatePrintNumVO updatePrintNumVO = new UpdatePrintNumVO();
            updatePrintNumVO.setBusinessOrder(initialInventoryDO.getBillNo());
            updatePrintNumVO.setMaterialsNo(detailDO.getMaterialsNo());
            updatePrintNumVO.setPrintNum(detailDO.getTotalQty());
            updatePrintNumVOList.add(updatePrintNumVO);
            rspList.addAll(printRef.get());
        }
        warehouseInboundDetailService.updatePrintNum(updatePrintNumVOList, orgId);
        resultRef.set(rspList);
        return ErrorCode.Success;
    }

    /**
     * 获取返回状态描述信息
     *
     * @param state Integer
     * @return String
     */
    private String getStateDesc(Integer state)
    {
        if (1 == state)
        {
            return "部分入库";
        }
        else if (2 == state)
        {
            return "已入库";
        }
        else if (3 == state)
        {
            return "强制结单";
        }
        else
        {
            return "未入库";
        }
    }

    /**
     * 打印期初条码以及总条码<br>
     *
     * @param initialInventoryDetailDO InitialInventoryDetailDO
     * @return ErrorCode
     */
    @Transactional(rollbackFor = Exception.class)
    private ErrorCode printBarcodeDOList(InitialInventoryDetailDO initialInventoryDetailDO, String orgId, String userId, String userName, InitialInventoryDO initialInventoryDO, Ref<List<BarcodeManageVO>> listRef)
    {
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode())
        {
            return ErrorCode.IllegalArument;
        }

        List<BarcodeManageVO> barcodeManageVOList = new ArrayList<>();
        BigDecimal totalMun = initialInventoryDetailDO.getTotalQty();
        BigDecimal minMun = initialInventoryDetailDO.getMinPackQty();
        String vinCode = initialInventoryDetailDO.getVinid();
        String orawyd = initialInventoryDetailDO.getOrawyd();

        if (totalMun.compareTo(BigDecimal.ZERO) <= 0 || minMun.compareTo(BigDecimal.ZERO) <= 0)
        {
            return ErrorCode.Success;
        }

        //查询零件英文描述
        String materialsNo = initialInventoryDetailDO.getMaterialsNo();
        String materialsDesEn = "";
        List<PubMaterialsDO> pubMaterialsDOS = pubMaterialsMapper.selectByMaterialsNos(Lists.newArrayList(materialsNo));
        if (CollectionUtils.isNotEmpty(pubMaterialsDOS)) {
            materialsDesEn = pubMaterialsDOS.get(0).getMaterialsDesEn();
        }


        String totalBarcode = textResult.getValue();
        BarcodeManageDO totalSingleBarcode = makeSingleBarcode(initialInventoryDetailDO, orgId, userId, userName, initialInventoryDO.getInLocation());

        totalSingleBarcode.setBarcode(totalBarcode);
        totalSingleBarcode.setTotalBarcode(totalBarcode);
        totalSingleBarcode.setTotalQty(totalMun);
        totalSingleBarcode.setCurrentQty(totalMun);
        totalSingleBarcode.setSeq(0);
        totalSingleBarcode.setPurchaseContractNo(initialInventoryDetailDO.getBatchNo());
        totalSingleBarcode.setMachineModel(initialInventoryDetailDO.getMachineType());
        totalSingleBarcode.setCountry(initialInventoryDO.getCountry());//国家
        totalSingleBarcode.setMaterialsDesEn(materialsDesEn);
        barcodeManageMapper.insert(totalSingleBarcode);
        BarcodeManageVO subBarcodeManageVO = new BarcodeManageVO();
        BeanUtils.copyProperties(totalSingleBarcode, subBarcodeManageVO);
        subBarcodeManageVO.setBatchNo(totalSingleBarcode.getPurchaseContractNo());
        subBarcodeManageVO.setDestinnation(totalSingleBarcode.getCountry());
//        subBarcodeManageVO.setVinid(vinCode);
        barcodeManageVOList.add(subBarcodeManageVO);

        BigDecimal packageCount = totalMun.divide(minMun, 0, BigDecimal.ROUND_DOWN);
        BigDecimal surplus = totalMun.subtract(minMun.multiply(packageCount));

        Integer seq=0;
        for (int i = 0; i < packageCount.intValue(); i++)
        {
            seq++;
            ActionResult<String> barcodeResult = fastGenClient.textGuid();
            if (textResult.getCode() != ErrorCode.Success.getCode())
            {
                return ErrorCode.IllegalArument;
            }
            String barcode = barcodeResult.getValue();

            BarcodeManageDO singleBarcode = makeSingleBarcode(initialInventoryDetailDO, orgId, userId, userName, initialInventoryDO.getInLocation());

            singleBarcode.setBarcode(barcode);
            singleBarcode.setTotalBarcode(totalBarcode);
            singleBarcode.setTotalQty(totalMun);
            singleBarcode.setCurrentQty(minMun);
            singleBarcode.setVinid(vinCode);
            singleBarcode.setOrawyd(orawyd);
            singleBarcode.setBarcodeFlag(1);
            singleBarcode.setSeq(seq);
            singleBarcode.setPurchaseContractNo(initialInventoryDetailDO.getBatchNo());
            singleBarcode.setMachineModel(initialInventoryDetailDO.getMachineType());
            singleBarcode.setCountry(initialInventoryDO.getCountry());//国家
            singleBarcode.setMaterialsDesEn(materialsDesEn);
            barcodeManageMapper.insert(singleBarcode);

            BarcodeManageVO barcodeManageVO = new BarcodeManageVO();
            BeanUtils.copyProperties(singleBarcode, barcodeManageVO);
            barcodeManageVO.setBatchNo(singleBarcode.getPurchaseContractNo());
            barcodeManageVO.setDestinnation(singleBarcode.getCountry());
            barcodeManageVOList.add(barcodeManageVO);
        }

        if (surplus.compareTo(BigDecimal.ZERO) > 0)
        {
            seq++;
            BarcodeManageDO singleBarcode = makeSingleBarcode(initialInventoryDetailDO, orgId, userId, userName, initialInventoryDO.getInLocation());
            ActionResult<String> barcodeResult = fastGenClient.textGuid();
            if (textResult.getCode() != ErrorCode.Success.getCode())
            {
                return ErrorCode.IllegalArument;
            }
            String barcode = barcodeResult.getValue();
            singleBarcode.setBarcode(barcode);
            singleBarcode.setTotalBarcode(totalBarcode);
            singleBarcode.setTotalQty(totalMun);
            singleBarcode.setCurrentQty(surplus);
            singleBarcode.setBarcodeFlag(1);
            singleBarcode.setVinid(vinCode);
            singleBarcode.setOrawyd(orawyd);
            singleBarcode.setSeq(seq);
            singleBarcode.setPurchaseContractNo(initialInventoryDetailDO.getBatchNo());
            singleBarcode.setMachineModel(initialInventoryDetailDO.getMachineType());
            singleBarcode.setCountry(initialInventoryDO.getCountry());//国家
            singleBarcode.setMaterialsDesEn(materialsDesEn);
            barcodeManageMapper.insert(singleBarcode);

            BarcodeManageVO barcodeManageVO = new BarcodeManageVO();
            BeanUtils.copyProperties(singleBarcode, barcodeManageVO);
            barcodeManageVO.setBatchNo(singleBarcode.getPurchaseContractNo());
            barcodeManageVO.setVinid(vinCode);
            barcodeManageVO.setDestinnation(singleBarcode.getCountry());
            barcodeManageVOList.add(barcodeManageVO);
        }
        String locationDesc="";
        WarehouseInboundDO inboundDO = warehouseInboundMapper.selectByOrder(initialInventoryDetailDO.getMainNo(), orgId);
        if(inboundDO!=null){
            locationDesc=barcodeManageMapper.locationDesc(initialInventoryDetailDO.getMaterialsNo(),orgId,inboundDO.getWarehouseCode());
        }
        for (BarcodeManageVO result:barcodeManageVOList
                ) {
            result.setChildCount(seq);
            result.setLocationDesc(locationDesc);
        }
        listRef.set(barcodeManageVOList);
        return ErrorCode.Success;
    }

    /**
     * 获取条码基本信息
     *
     * @param inventoryDetailDO InitialInventoryDetailDO
     * @param orgId             String
     * @param userId            String
     * @param userName          String
     * @param warehouseCode     String
     * @return BarcodeManageDO
     */
    private BarcodeManageDO makeSingleBarcode(InitialInventoryDetailDO inventoryDetailDO, String orgId, String userId, String userName, String warehouseCode)
    {
        BarcodeManageDO barcodeManageDO = new BarcodeManageDO();
        barcodeManageDO.setOrgId(orgId);
        barcodeManageDO.setBillType("XGQR");
        barcodeManageDO.setBillId(inventoryDetailDO.getMainId());
        barcodeManageDO.setBillNo(inventoryDetailDO.getMainNo());
        barcodeManageDO.setBarcodeFlag(0);
        barcodeManageDO.setMaterialsNo(inventoryDetailDO.getMaterialsNo());
        barcodeManageDO.setMaterialsDes(inventoryDetailDO.getMaterialsDes());
        barcodeManageDO.setTotalQty(inventoryDetailDO.getTotalQty());
        barcodeManageDO.setCurrentQty(inventoryDetailDO.getTotalQty());
        barcodeManageDO.setLeftQty(new BigDecimal(0));
        barcodeManageDO.setWarehouseCode(warehouseCode);
        barcodeManageDO.setPrintId(userId);
        barcodeManageDO.setPrintName(userName);
        barcodeManageDO.setPrintTime(new Date());
        barcodeManageDO.setReprintCount(0);
        barcodeManageDO.setBarcodeStatus(BarcodeStatus.Status.Printed.toString());
        DataDictionaryDO dataDictionaryDO = dataDictionaryMapper.itemByCode(BarcodeStatus.Status.Name.toString(), barcodeManageDO.getBarcodeStatus());
        if (dataDictionaryDO != null)
        {
            barcodeManageDO.setStatusDesc(dataDictionaryDO.getName());
        }
        barcodeManageDO.setCreateId(userId);
        barcodeManageDO.setCreateName(userName);
        barcodeManageDO.setCreateTime(new Date());
        barcodeManageDO.setIsDel(false);
        barcodeManageDO.setIsSeparate(false);
        return barcodeManageDO;
    }


    /**
     * 添加期初入库
     *
     * @param detailVOs List<InitialInventoryDetailVO> 入库零件信息
     * @param location  String 入库仓库信息
     * @param orgId     String 企业ID
     * @param userId    String 用户ID
     * @param deptName  String 部门ID
     * @param remark    String 备注
     * @return ErrorCode
     * @throws Exception Exception
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode add(List<InitialInventoryDetailVO> detailVOs, String location, String orgId, String userId, String deptName, String remark, String userName,String area,String sapCode,String country) throws Exception
    {
        InitialInventoryDO initialInventoryDO = new InitialInventoryDO();
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (null == textResult || textResult.getCode() != 0)
        {
            throw new Exception("生成期初入库单ID失败!");
        }
        String billId = textResult.getValue();
        String billNo = genDocumentService.genDocumentNo(BillDesc.InitialInventory, orgId);
        initialInventoryDO.setBillNo(billNo);
        initialInventoryDO.setOrgId(orgId);
        initialInventoryDO.setCreateId(userId);
        initialInventoryDO.setCreateName(userName);
        initialInventoryDO.setInLocation(location);
        initialInventoryDO.setDept(deptName);
        initialInventoryDO.setRemark(remark);
        initialInventoryDO.setId(billId);
        initialInventoryDO.setInArea(area);
        initialInventoryDO.setSapInArea(sapCode);
        initialInventoryDO.setCountry(country);
        int addRet = initialInventoryMapper.insert(initialInventoryDO);
        if (0 >= addRet)
        {
            return ErrorCode.InsertBillFail;
        }

        ErrorCode addCode = initialInventoryDetailService.add(detailVOs, billNo, billId, orgId, location, userId, userName);
        if (ErrorCode.Success != addCode)
        {
            return addCode;
        }

        WarehouseInboundAddVO warehouseInboundAddVO = getWarehouseInboundAddVO(initialInventoryDO, detailVOs);

        //添加入库事务单
        ErrorCode inboundCode = warehouseInboundService.add(warehouseInboundAddVO, userId, orgId);
        if (ErrorCode.Success != inboundCode)
        {
            return inboundCode;
        }
        return ErrorCode.Success;
    }

    /**
     * 导入数据，成功则返回成功数据，失败则返回失败数据
     *
     * @param in      InputStream
     * @param orgId   String
     * @param codeRef Ref<ErrorCode>
     * @return List<InitialInventoryDetailVO>
     * @throws Exception Exception
     */
    public List<InitialInventoryDetailVO> importExcel(InputStream in, String orgId, Ref<ErrorCode> codeRef) throws Exception
    {
        HSSFWorkbook wb = new HSSFWorkbook(in);
        if (null == wb)
        {
            codeRef.set(ErrorCode.ImportTemplateError);
            return new ArrayList<>();
        }
        HSSFSheet sheet = wb.getSheetAt(0);

        int totalRow = sheet.getLastRowNum();
        if (totalRow < 2)
        {
            codeRef.set(ErrorCode.ImportTemplateError);
            return new ArrayList<>();
        }
        int totalCell = sheet.getRow(1).getLastCellNum();
        if (totalCell != 10)
        {
            codeRef.set(ErrorCode.ImportTemplateError);
            return new ArrayList<>();
        }
        List<InitialInventoryDetailVO> detailVOList = new ArrayList<>();
        List<InitialInventoryDetailVO> errorDetailVOList = new ArrayList<>();
        for (int i = 2; i <= totalRow; i++)
        {
            HSSFRow curRow = sheet.getRow(i);
            StringBuffer remarkBuffer = new StringBuffer();
            InitialInventoryDetailVO detailVO = new InitialInventoryDetailVO();
            if (curRow == null)
            {
                continue;
            }
            String no = getCellValue(curRow, 0);
            String materialsNo = getCellValue(curRow, 1);
            String totalQty = getCellValue(curRow, 3);
            String minPackQty = getCellValue(curRow, 4);
            String orawyd = getCellValue(curRow, 5);
            String vinid = getCellValue(curRow, 6);
            String unitPrice = getCellValue(curRow, 7);
            //批次号
            String batchNo = getCellValue(curRow, 8);
            //适用机型
            String machineType = getCellValue(curRow, 9);

            if (StringUtil.isNullOrEmpty(no) && StringUtil.isNullOrEmpty(materialsNo) && StringUtil.isNullOrEmpty(totalQty) && StringUtil.isNullOrEmpty(minPackQty) && StringUtil.isNullOrEmpty(orawyd) && StringUtil.isNullOrEmpty(vinid))
            {
                continue;
            }

            if (StringUtil.isNullOrEmpty(no))
            {
                remarkBuffer.append("序号不能为空");
            }
            if (StringUtil.isNullOrEmpty(materialsNo))
            {
                remarkBuffer.append("，");
                remarkBuffer.append("零件编码不能为空");
            }

            if(materialsNo.length()>20)
            {
                remarkBuffer.append("，");
                remarkBuffer.append("零件编码长度不能超过20");
            }
            if (StringUtil.isNullOrEmpty(totalQty))
            {
                remarkBuffer.append("，");
                remarkBuffer.append("入库数量不能为空");
            }
            else if (!isInteger(totalQty))
            {
                remarkBuffer.append("，");
                remarkBuffer.append("入库数量格式不正确");
            }
            else if (new BigDecimal(totalQty).compareTo(BigDecimal.valueOf(9999999))>0)
            {
                remarkBuffer.append("，");
                remarkBuffer.append("入库数量不能大于7位数");
            }

            if(orawyd.length()>20)
            {
                remarkBuffer.append("，");
                remarkBuffer.append("图号长度不能超过20");
            }
            if(vinid.length()>25)
            {
                remarkBuffer.append("，");
                remarkBuffer.append("VIN号长度不能超过25");
            }

            if (StringUtil.isNullOrEmpty(minPackQty))
            {
                remarkBuffer.append("，");
                remarkBuffer.append("最小包装数不能为空");
            }
            else if (!isInteger(minPackQty))
            {
                remarkBuffer.append("，");
                remarkBuffer.append("最小包装数格式不正确");
            }
            else if (new BigDecimal(minPackQty).compareTo(BigDecimal.valueOf(9999999))>0)
            {
                remarkBuffer.append("，");
                remarkBuffer.append("最小包装数不能大于7位数");
            }
            else if (new BigDecimal(minPackQty).compareTo(new BigDecimal(totalQty))>0)
            {
                remarkBuffer.append("，");
                remarkBuffer.append("最小包装数量不能大于入库数量");
            }

            if (StringUtil.isNullOrEmpty(unitPrice))
            {
                remarkBuffer.append("，");
                remarkBuffer.append("单价不能为空");
            }
            else if (!isInteger(unitPrice))
            {
                remarkBuffer.append("，");
                remarkBuffer.append("单价格式不正确");
            }
            else if (new BigDecimal(unitPrice).compareTo(BigDecimal.valueOf(99999999))>0)
            {
                remarkBuffer.append("，");
                remarkBuffer.append("单价不能大于8位数");
            }


            MaterialsVO materialsVO = materialsService.itemByNo(materialsNo.trim(), orgId.trim());
            if (materialsVO == null)
            {
                remarkBuffer.append("，");
                remarkBuffer.append("零件不存在");
            }

            if (!StringUtil.isNullOrSpace(remarkBuffer.toString()))
            {
                detailVO.setErrorRow(i + 1);
                detailVO.setRemark(remarkBuffer.toString());
                errorDetailVOList.add(detailVO);
                continue;
            }

            detailVO.setTotalQty(new BigDecimal(totalQty));
            detailVO.setMinPackQty(new BigDecimal(minPackQty));
            detailVO.setOrawyd(orawyd);
            detailVO.setVinid(vinid);
            detailVO.setOrgId(orgId);

            detailVO.setMaterialsNo(materialsVO.getMaterialsNo());
            detailVO.setMaterialsDes(materialsVO.getMaterialsDes());
            detailVO.setMaterialsType(materialsVO.getMaterialsType());
            detailVO.setUnit(materialsVO.getUnit());
            detailVO.setUnitPrice(new BigDecimal(unitPrice));
            detailVO.setBatchNo(batchNo);
            detailVO.setMachineType(machineType);
            detailVOList.add(detailVO);
        }

        if (ListUtil.isNullOrEmpty(errorDetailVOList))
        {
            detailVOList = ImportUtil.deRepeat(detailVOList,"MaterialsNo","TotalQty",null,null);
            codeRef.set(ErrorCode.Success);
        }
        else
        {
            detailVOList = errorDetailVOList;
            codeRef.set(ErrorCode.ImportDataError);
        }
        return detailVOList;
    }


    private boolean isInteger(String str)
    {
        if (null == str || "".equals(str)) {
            return false;
        }
        try {
            BigDecimal decimal = new BigDecimal(str);
            if(decimal.compareTo(BigDecimal.ZERO) == 0){
                return false;
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }

    /**
     * 判断字符对应的数字是否大于比较的数字<br>
     * if str > maxValue  return "true"
     *
     * @param str      String
     * @param maxValue int
     * @return boolean
     */
    private boolean checkMaxValue(String str, int maxValue)
    {
        if (!isInteger(str))
        {
            return false;
        }
        Double value = Double.parseDouble(str);

        if (value - maxValue > 0)
        {
            return true;
        }
        return false;
    }

    /**
     * 比较两个字符对应的数字大小
     * <br>if source > target return "true"
     *
     * @param source String
     * @param target String
     * @return boolean
     */
    private boolean compareString(String source, String target)
    {
        if (!isInteger(source) || !isInteger(target))
        {
            return false;
        }
        Double doubleSource = Double.parseDouble(source);
        Double doubleTarget = Double.parseDouble(target);

        if (doubleSource.compareTo(doubleTarget) > 0)
        {
            return true;
        }

        return false;
    }

    private String getCellValue(HSSFRow curRow, int i)
    {
        String value = "";
        if (curRow.getCell(i) != null)
        {
            curRow.getCell(i).setCellType(CellType.STRING);
            value = curRow.getCell(i).getStringCellValue();
        }
        return value;
    }


    /**
     * 生成入库单信息
     *
     * @param detailVOs          List<InitialInventoryDetailVO>
     * @param initialInventoryDO InitialInventoryDO
     * @return WarehouseInboundAddVO
     */
    private WarehouseInboundAddVO getWarehouseInboundAddVO(InitialInventoryDO initialInventoryDO, List<InitialInventoryDetailVO> detailVOs)
    {
        WarehouseInboundAddVO addVO = new WarehouseInboundAddVO();
        WarehouseInboundVO headVO = new WarehouseInboundVO();
        List<WarehouseInboundDetailVO> detailVOList = new ArrayList<>();

        String businessSingle = initialInventoryDO.getBillNo().substring(0, 4);
        String businessOrder = initialInventoryDO.getBillNo();

        headVO.setBusinessSingle(businessSingle);
        headVO.setBusinessOrder(businessOrder);
        headVO.setWarehouseCode(initialInventoryDO.getInLocation());
        headVO.setInArea(initialInventoryDO.getInArea());
        headVO.setSapInArea(initialInventoryDO.getSapInArea());

        BigDecimal num = BigDecimal.ZERO;
        if (!ListUtil.isNullOrEmpty(detailVOs))
        {
            for (InitialInventoryDetailVO detailVO : detailVOs)
            {
                WarehouseInboundDetailVO addDetailVO = new WarehouseInboundDetailVO();
                addDetailVO.setBusinessSingle(businessSingle);
                addDetailVO.setBusinessOrder(businessOrder);
                addDetailVO.setMaterialNo(detailVO.getMaterialsNo());
                addDetailVO.setMaterialName(detailVO.getMaterialsDes());
                addDetailVO.setMaterialType(detailVO.getMaterialsType());
                addDetailVO.setUnit(detailVO.getUnit());
                addDetailVO.setAmount(detailVO.getTotalQty());
                addDetailVO.setRealAmount(BigDecimal.ZERO);
                addDetailVO.setCreaterName(initialInventoryDO.getCreateName());
                addDetailVO.setCreaterId(initialInventoryDO.getCreateId());
                addDetailVO.setTotalPrice(detailVO.getTotalQty().multiply(detailVO.getUnitPrice()));
                num = num.add(detailVO.getTotalQty());
                detailVOList.add(addDetailVO);
            }
        }
        headVO.setAmount(num);
        addVO.setHeaderInfo(headVO);
        addVO.setDetailList(detailVOList);
        return addVO;
    }

    /**
     * 获取零件编码的列表
     *
     * @param materialsNos String 零件编码字符
     * @return List<String>
     */
    private List<String> getMaterialsNoList(String materialsNos)
    {
        String[] materials = materialsNos.split(",");
        List<String> materialNoList = new ArrayList<>();

        for (String materialNo : materials)
        {
            materialNoList.add(materialNo.trim());
        }
        return materialNoList;
    }

    /**
     * 更新入库事务单，同时更新期初入库业务单信息
     *
     * @param returnNo    String
     * @param materialNo  String
     * @param realAmount  String
     * @param singelState String
     * @param totalState  String
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean updateByInbound(String returnNo, String materialNo, BigDecimal realAmount, Integer singelState, Integer totalState) throws Exception
    {
        InitialInventoryDetailVO detailVO = new InitialInventoryDetailVO();
        detailVO.setMainNo(returnNo);
        detailVO.setMaterialsNo(materialNo);
        InitialInventoryDetailDO inDetailDO = initialInventoryDetailMapper.itemByNo(returnNo, materialNo);
        if (null == inDetailDO)
        {
            return false;
        }
        if (realAmount.compareTo(inDetailDO.getTotalQty()) > 0)
        {
            throw new Exception("实际入库数量不能大于计划入库数量");
        }
        inDetailDO.setInNum(realAmount);
        inDetailDO.setState(singelState);
        boolean success = initialInventoryDetailMapper.update(inDetailDO) > 0;
        if (success)
        {
            InitialInventoryDO returnInDO = initialInventoryMapper.itemByNo(returnNo);
            if (null == returnInDO)
            {
                return false;
            }
            returnInDO.setState(totalState);
            success = initialInventoryMapper.update(returnInDO) > 0;
        }
        return success;
    }

    /**
     * 期初入库模板下载
     *
     * @throws Exception
     */
    public void download() throws Exception
    {
        FileUtil.downLoadFile(response, filePath, templateExcelFileName);
    }

    /**
     * 下载打印模板
     *
     * @throws Exception
     */
    public void downPrintDrives() throws Exception
    {
        FileUtil.downLoadFile(response, filePath, drivesName);
    }

    /**
     * 手动完成单据<br>
     *     materialsNo 不为null,则更改该单据下的零件状态为“手动完成”状态；如果materialsNo为空，则更改整个单据为“手动完成”状态
     * @param billNo  String 单据编号
     * @param materialsNo String 零件编号
     * @param orgId String 企业ID
     * @return ErrorCode 返回码
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode manualFinish(String billNo,String materialsNo,String orgId)throws Exception
    {
        if (StringUtil.isNullOrEmpty(materialsNo))//零件编码为空，更新单据状态为“手动完成”
        {
            initialInventoryMapper.updateStatus(3, billNo);
            warehouseInboundService.updateState(billNo, 3, orgId);

            initialInventoryDetailMapper.updateStatus(3, billNo, null, orgId);
            warehouseInboundDetailMapper.updateAllStatus(3, billNo, orgId);
        }
        else
        {
            initialInventoryDetailMapper.updateStatus(3, billNo, materialsNo, orgId);
            warehouseInboundService.updateDetailState(billNo, materialsNo, null, 3, orgId);
            ErrorCode errorCode = checkBillFinished(billNo, orgId);

            if (ErrorCode.Success != errorCode)
            {
                return errorCode;
            }
        }
        return ErrorCode.Success;
    }

    /**
     * 校验单据是否已完成<br>
     *     判断单据下的所有零件是否已经完成，如果都完成，则更改单据状态为完成
     * @param billNo String
     * @param orgId String
     * @return Boolean
     */
    private ErrorCode checkBillFinished(String billNo,String orgId)throws Exception
    {
        List<InitialInventoryDetailDO> detailDOs = initialInventoryDetailMapper.listByBillNo(billNo);
        if(ListUtil.isNullOrEmpty(detailDOs)){
            throw new Exception("未查询到期初入库单详情列表");
        }
        boolean manul = false;
        boolean flag = true;
        int status;
        for (InitialInventoryDetailDO temp : detailDOs)
        {
            if(temp.getState() == 3){
                manul = true;
            }
            if (2==temp.getState() || 3==temp.getState())
            {
                //完成状态
                continue;
            }
            flag =false;
        }
        if(flag){
            if(manul){
                status = 3;
            }else{
                status = 2;
            }
        }else{
            status = 1;
        }
        initialInventoryMapper.updateStatus(status,billNo);
        warehouseInboundService.updateState(billNo,status,orgId);
        return ErrorCode.Success;
    }

    public InitialInventoryDetailDO getInitialInventoryDetailDO(String returnNo, String materialNo) throws Exception
    {
        return initialInventoryDetailMapper.itemByNo(returnNo, materialNo);
    }

    public InitialInventoryDO getInitialInventoryById(String id){
        if(StringUtils.isEmpty(id)){
            return null;
        }
        InitialInventoryDO initialInventory = initialInventoryMapper.item(id);
        return initialInventory;
    }

    public List<InitialInventoryDetailDO> selectNeedInboundsByMainId(String mainId){
        if(StringUtils.isEmpty(mainId)){
            return Collections.EMPTY_LIST;
        }
        return initialInventoryDetailMapper.selectNeedInboundsByMainId(mainId);
    }



    @Transactional(rollbackFor = Exception.class)
    @Async
    public void initialInventoryAutoInbound(InitialInventoryDO initialInventory,List<InitialInventoryDetailDO> initialInventoryDetails,String lockKey) throws Exception {
        RLock lock = redissonClient.getLock(lockKey);
        boolean isLock;
        try {
            isLock = lock.tryLock(0,RedisConstant.INITIALINVENTORY_INBOUND_LOCK_TIME, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            log.error("期初入库自动入库获取分布式锁异常{}",e);
            return ;
        }
        if(!isLock){
            log.warn("期初入库自动入库存在已经执行的任务,无法获取锁，本次不执行");
            return ;
        }
        try{
            String orgId = initialInventory.getOrgId();
            String inLocation = initialInventory.getInLocation();
            String inArea = initialInventory.getInArea();
            String billNo = initialInventory.getBillNo();
            int handledNum = 0;//用于统计已经处理的数量，一次只处理一千条，超过一千条就跳出方法
            breakLable:
            for(InitialInventoryDetailDO detail : initialInventoryDetails){
                //根据零件和单据号查询条码
                String materialsNo = detail.getMaterialsNo();
                //零件加仓库+库区获取默认储位，如果没有默认储位则不自动入库
                MaterialLocationRelationDO defaultLocation = materialLocationRelationMapper.findDefaultLocation(materialsNo, inLocation, inArea, orgId);
                if(defaultLocation == null){
                    inboundWarnLogWrite("入库单:"+billNo+"零件:"+materialsNo+"入库储位为空,不进行入库操作");
                    continue;
                }
                String locationCode = defaultLocation.getLocationCode();
                if(StringUtils.isEmpty(locationCode)){
                    inboundWarnLogWrite("入库单:"+billNo+"零件:"+materialsNo+"入库储位为空,不进行入库操作");
                    continue;
                }
                //使用查询到的默认储位的仓库编码和库区编码覆盖单据的仓库和库区编码（如果单据没有库区，此处会赋值）
                inLocation = defaultLocation.getWarehouseCode();
                inArea = defaultLocation.getAreaCode();
                Integer detailState = detail.getState();
                if(detailState == null || (detailState.compareTo(0) != 0 && detailState.compareTo(1) != 0)){
                    inboundWarnLogWrite("入库单:"+billNo+"零件:"+materialsNo+"入库状态为"+detailState+"不进行入库操作");
                    continue;
                }
                //根据业务单号和零件编码查询入库详情记录
                WarehouseInboundDetailVO tempVO = new WarehouseInboundDetailVO();
                tempVO.setBusinessOrder(billNo);
                tempVO.setMaterialNo(materialsNo);
                tempVO.setOrgId(orgId);
                List<WarehouseInboundDetailDO> detailList = warehouseInboundDetailMapper.list(tempVO);
                if (ListUtil.isNullOrEmpty(detailList)) {
                    inboundWarnLogWrite("入库单:"+billNo+"零件:"+materialsNo+"没有入库事务详情表不进行入库操作");
                    continue;
                }
                WarehouseInboundDetailDO inboundDetail = detailList.get(0);
                if (inboundDetail.getStatus() == 2) {
                    inboundWarnLogWrite("入库单:"+billNo+"零件:"+materialsNo+"入库事务详情表的状态为2，不进行自动入库操作");
                    continue;
                }
                if (inboundDetail.getStatus() == 3) {
                    inboundWarnLogWrite("入库单:"+billNo+"零件:"+materialsNo+"入库事务详情表的状态为3，不进行自动入库操作");
                    continue;
                }
                String mainNo = detail.getMainNo();
                //判断条码状态是否为已打印，已打印的条码才能入库，判断条码的所属单据是否为对应业务单据
                List<BarcodeManageDO> barcodes = barcodeManageMapper.selectByBusinessOrderMatOrgId(mainNo, materialsNo, orgId);
                if(CollectionUtils.isEmpty(barcodes)){
                    inboundWarnLogWrite("入库单:"+billNo+"零件:"+materialsNo+"没有已打印条码，不进行自动入库操作");
                    continue;
                }
                //条码入库操作
                for(BarcodeManageDO barcode : barcodes){
                    if(handledNum - 999 > 0){
                        log.info("handledNum处理数量超过1000条，跳出运行");
                        break breakLable;
                    }
                    String barcodeStatus = barcode.getBarcodeStatus();
                    if(barcodeStatus == null || !"0".equals(barcodeStatus)){
                        inboundWarnLogWrite("入库单:"+billNo+"零件:"+materialsNo+"对应条码:"+barcode.getBarcode()+"状态不是已打印状态，不进行入库操作");
                        continue;
                    }
                    WarehouseInboundRecordAddVO inboundRecordAdd = new WarehouseInboundRecordAddVO();
                    inboundRecordAdd.setBarCode(barcode.getBarcode());
                    inboundRecordAdd.setAmount(barcode.getCurrentQty());
                    inboundRecordAdd.setLocationCode(locationCode);
                    inboundRecordAdd.setBusinessOrder(billNo);
                    inboundRecordAdd.setFrozen(0);
                    inboundRecordAdd.setCrucialDevice((short)0);
                    inboundRecordAdd.setLocationCode(locationCode);
                    initialInventoryAutoBound(inboundRecordAdd,inboundDetail,detail,orgId,inLocation,inArea,barcode);
                    handledNum++;
                    log.info("handledNum数量为:{}",handledNum);
                }
            }
            //查看个零件的入库状态，用于更新业务主表的业务状态和入库事务主表的状态
            WarehouseInboundDetailVO detailVO = new WarehouseInboundDetailVO();
            detailVO.setBusinessOrder(billNo);
            detailVO.setOrgId(orgId);
            List<WarehouseInboundDetailDO> details = warehouseInboundDetailMapper.list(detailVO);
            Integer noInboundNum = 0;
            Integer partInboundNum = 0;
            Integer allInboundNum = 0;
            boolean forceFinishLable = false;//强制完成标记： false非强制，true强制完成
            for(WarehouseInboundDetailDO model : details){
                Integer status = model.getStatus();
                BigDecimal amount = model.getAmount();
                BigDecimal realAmount = model.getRealAmount();
                if(status ==3){
                    forceFinishLable=true;//强制完成
                    allInboundNum ++;
                }else{
                    int sub = amount.compareTo(realAmount);
                    if(realAmount.compareTo(BigDecimal.ZERO) == 0){
                        noInboundNum++;
                    } else if(sub == 0){
                        allInboundNum ++;
                    }else{
                        partInboundNum++;
                    }
                }
            }
            Integer mainInboundStatus;
            int detailSize = details.size();
            if(noInboundNum.compareTo(detailSize) == 0){
                mainInboundStatus = 0;
            }else if(allInboundNum.compareTo(detailSize) == 0){
                if(forceFinishLable){
                    mainInboundStatus = 3;
                }else{
                    mainInboundStatus = 2;
                }
            }else{
                mainInboundStatus = 1;
            }
            //更新入库事务主表信息
            autoUpdateWarehouseInbound(billNo,orgId,mainInboundStatus);
            //更新业务主表状态信息
            InitialInventoryDO returnInDO = initialInventoryMapper.itemByNo(billNo);
            if (null == returnInDO){
                inboundErrorLogWrite("期初入库单:"+billNo+"未查询导入库事务主表");
                throw new Exception("期初入库单:"+billNo+"未查询导入库事务主表");
            }
            returnInDO.setState(mainInboundStatus);
            boolean success = initialInventoryMapper.update(returnInDO) > 0;
            if(!success){
                inboundErrorLogWrite("期初入库单:"+billNo+"更新主表入库状态失败");
                throw new Exception("期初入库单:"+billNo+"更新主表入库状态失败");
            }
        }catch (Exception e){
            throw new Exception(e);
        }finally {
            lock.unlock();
        }
    }

    private void autoUpdateWarehouseInbound(String billNo,String orgId,Integer inboundStatus) throws Exception {
        WarehouseInboundVO inboundVO = new WarehouseInboundVO();
        inboundVO.setBusinessOrder(billNo);
        inboundVO.setOrgId(orgId);
        List<WarehouseInboundDO> inboundList = warehouseInboundService.list(inboundVO);
        if(ListUtil.isNullOrEmpty(inboundList)){
            inboundErrorLogWrite("期初入库单:"+billNo+"未查询导入库事务主表");
            throw new Exception("期初入库单:"+billNo+"未查询导入库事务主表");
        }
        WarehouseInboundDO inboundDO = inboundList.get(0);
        inboundDO.setStatus(inboundStatus);
        boolean success = warehouseInboundService.updateByPK(inboundDO);
        if(!success){
            inboundErrorLogWrite("期初入库单:"+billNo+"更新入库事务主表异常");
            throw new Exception("期初入库单:"+billNo+"更新入库事务主表异常");
        }
    }

    private void inboundWarnLogWrite(String errorMsg){
        inboundErrorLogWrite("^^^^warn^^^^",errorMsg);

    }
    
    private void inboundErrorLogWrite(String errorMsg){
        inboundErrorLogWrite("****ERROR*****",errorMsg);
    }

    private void inboundErrorLogWrite(String logLevel,String errorMsg){
        errorMsg = logLevel+(new Date()).toString() + ":::::::"+errorMsg+"\n";
        File file =new File(filePath+INITIALINVENROTY_INBOUND_ERROR_LOG);
        FileOutputStream fop = null;
        try {
            fop = new FileOutputStream(file,true);
            if (!file.exists()) {
                file.createNewFile();
                errorMsg = "#该文件用于期初入库时记录自动入库的错误日志记录，方便入库后查看异常数据定位问题,可以随意删除，不影响\n"+errorMsg;
            }
            byte[] contentInBytes = errorMsg.getBytes();
            fop.write(contentInBytes);
            fop.flush();
            fop.close();
        } catch (Exception e) {
            log.error("期初入库自动入库写文件异常"+e);
        } finally {
            try {
                if (fop != null) {
                    fop.close();
                }
            } catch (IOException e) {
                log.error("期初入库自动入库写文件异常"+e);
            }
        }

    }

    /**
     * @Des 期初入库自动入库处理
     * @Date 2021/2/8 14:36
     * @Author wangzhaoyu
     * @Param [warehouseInboundRecordAddVO]
     * @Return void
     */
    @Transactional
    public void initialInventoryAutoBound(WarehouseInboundRecordAddVO warehouseInboundRecordAddVO,WarehouseInboundDetailDO inboundDetail,
                                           InitialInventoryDetailDO inDetailDO,String orgId,String warehouseCode,String areaCode,BarcodeManageDO barcode) throws Exception {

        WarehouseInboundRecordDO warehouseInboundRecordDO = new WarehouseInboundRecordDO();
        BeanUtils.copyProperties(inboundDetail, warehouseInboundRecordDO);
        BeanUtils.copyProperties(warehouseInboundRecordAddVO, warehouseInboundRecordDO);
        ActionResult<String> textResult = fastGenClient.textGuid();
        warehouseInboundRecordDO.setWarehouseCode(warehouseCode);
        warehouseInboundRecordDO.setAreaCode(areaCode);
        warehouseInboundRecordDO.setId(textResult.getValue());
        warehouseInboundRecordDO.setBarCode(barcode.getBarcode());
        warehouseInboundRecordDO.setCreateDate(new Date());
        warehouseInboundRecordDO.setCreaterId("自动入库");
        warehouseInboundRecordDO.setOrgId(orgId);
        warehouseInboundRecordDO.setCreaterName("自动入库");
        warehouseInboundRecordDO.setRowNo(barcode.getRowNo());

        //新增入库记录
        boolean isSuccess = warehouseInboundRecordMapper.insert(warehouseInboundRecordDO) > 0;
        if(!isSuccess){
            inboundErrorLogWrite("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"插入入库记录失败");
            throw new Exception("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"插入入库记录失败");
        }

        //更新条码状态
        barcode.setBarcodeStatus(BarcodeStatus.Status.InStorage.toString());
        barcode.setStatusDesc("已入库");
        barcode.setInboundUser("自动入库");
        barcode.setLatestInTime(warehouseInboundRecordDO.getCreateDate());
        boolean barcodeStatusResult = barcodeManageMapper.update(barcode) > 0;
        if(!barcodeStatusResult){
            inboundErrorLogWrite("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"更新条码状态失败");
            throw new Exception("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"更新条码状态失败");
        }
        //更新库存信息
        isSuccess = warehouseInventoryService.saveByInbound(warehouseInboundRecordDO, null, "自动入库");
        if(!isSuccess){
            inboundErrorLogWrite("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"更新库存失败");
            throw new Exception("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"更新库存失败");
        }
        BigDecimal inobundAmount = warehouseInboundRecordAddVO.getAmount();
        //更新入库事务详情表信息
        BigDecimal totalAmount = inboundDetail.getAmount();
        BigDecimal realAmount = inboundDetail.getRealAmount();
        BigDecimal sub = inobundAmount.add(realAmount);
        Integer detailInboundStatus ;
        if(sub.compareTo(totalAmount) > 0){
            inboundErrorLogWrite("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"实际入库数量不能大于计划入库数量");
            throw new Exception("实际入库数量不能大于计划入库数量");
        }else if(sub.compareTo(totalAmount) == 0){
            detailInboundStatus = 2;
        }else{
            detailInboundStatus = 1;
        }
        inboundDetail.setRealAmount(sub);
        inboundDetail.setStatus(detailInboundStatus);
        isSuccess = warehouseInboundDetailMapper.updateByPrimaryKeySelective(inboundDetail)>0;
        if(!isSuccess){
            inboundErrorLogWrite("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"更新入库事务详情表入库状态和入库数量异常");
            throw new Exception("更新入库事务详情表入库状态和入库数量异常");
        }
        //更新单据详情信息
        BigDecimal totalQty = DecimalUtil.getDecimal(inDetailDO.getTotalQty());
        if (realAmount.compareTo(totalQty) > 0){
            inboundErrorLogWrite("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"实际入库数量不能大于计划入库数量");
            throw new Exception("实际入库数量不能大于计划入库数量");
        }
        inDetailDO.setInNum(sub);
        inDetailDO.setState(detailInboundStatus);
        isSuccess = initialInventoryDetailMapper.update(inDetailDO) > 0;
        if(!isSuccess){
            inboundErrorLogWrite("期初入库单:"+warehouseInboundRecordDO.getBusinessOrder()+",零件号:"+warehouseInboundRecordDO.getMaterialNo()+"期初入库自动入库更新入库单详情表状态异常");
            throw new Exception("期初入库自动入库更新入库单详情表状态异常");
        }
    }

}
